This type of testing is useful in carrying out the
same test multiple times with different input data from a data source.
The data source can have any number of records or data row for which we
wanted the test to be carried out.
Instead of passing each data
row values to the test application and executing entire test for each
data row, we can link the test method to the data source. So when the
test is run, the test method will take the data row one by one from the
data source and will carry out the test for that many numbers of times
with different input values.
This is similar to the web
testing or load testing with data source attaching to the web method
parameters. This could be used in case of testing number of user
scenarios with different user logins to check the access permission or
to see the validation based on the user roles, if anything is applicable
to the application.
There are two different ways of
configuring the data source or attaching the source to the test method.
Let us consider one simple example of a method which takes two
parameters as quantity and unit price. The result of the method would be
returning the multiplied value of these two values and applying a
percentage of tax on it.
public double CalculateTotalPrice(double uPrice, int Qty)
{
double totalPrice;
double tax = 0.125;
totalPrice = uPrice * Qty + (uPrice * tax * Qty); //
return totalPrice;
}
Create a unit test for the above example. The unit test code would contain the following code for the above method:
[TestMethod()]
public void CalculateTotalPriceTest()
{
Class1 target = new Class1();
double uPrice = 0F;
int Qty = 0;
double expected = 0F;
double actual;
actual = target.CalculateTotalPrice(uPrice, Qty);
Assert.AreEqual(expected, actual);
}
Before setting the
properties, we have to create the data source. The data source can be of
different format like CSV, XML, Microsoft Access, Microsoft SQL Server
Database or Oracle Database, or any other database. For this example, we
will consider a CSV file having five records with UnitPrice, Quantity, ExpectedTotalPrice. These are values required in the test method.
Now the new unit test would also be listed in the Test View and Test List Editor. Open the Test View or Test List Editor using the Test menu option from the IDE. Select the test method from the list and open the Properties window. From the list of properties listed for the unit test, select the connection property, and choose the option to open the Data Source
wizard. From the wizard, select the data source type as CSV file from
the options. Select the CSV file we created from the location. This will
show the preview of the data too. Now the property of the test would be
like the window shown below:
Data Provider Name:
This property is disabled as we have selected the file directly and
made the connection. Visual Studio automatically assigns the Data Provider Name as Microsoft.VisualStudio.TestTools.DataSource.CSV.
Data Table Name:
After making the connection, we can see the tables listed from the
database connected. The table that we select from the list will be the
source of data for the testing.
Data Access Method:
This can be Sequential or Dynamic. This is the method that will be used
for retrieving the data from the data source for the test.
When we keep changing the properties of the test, we can see the properties added as attributes to the test method.
[DeploymentItem("TestProject\\Data.csv"), DataSource("Microsoft.VisualStudio.TestTools.DataSource. CSV", "|DataDirectory|\\Data.csv",
"Data#csv", DataAccessMethod.Sequential), TestMethod()]
public void CalculateTotalPriceTest()
{
}
The data source which is a CSV
file is added as the deployment item. The other attributes specify the
method of data access and the namespace used. These are the method level
attributes set for the test run.
To
set the value of the data from the data source to the test method,
modify the test method little bit as shown below. The
testContextInstance.DataRow
is used to fetch the value from the current row for the current
instance of the test. For example, if we have five rows in the data
source there would be five different instances of tests one for each
row.
I have added a custom error message to the assert to get the actual and expected values in case if the test fails.
[DataSource("Microsoft.VisualStudio.TestTools.DataSource. CSV", "|DataDirectory|\\Data.csv", "Data#csv", DataAccessMethod.Sequential),
DeploymentItem("TestProject1\\Data.csv"), TestMethod()]
public void CalculateTotalPriceTest()
{
Class1 target = new Class1();
double uPrice = 0F;
int Qty = 0;
double expected = 0F;
double actual;
expected = Convert.ToDouble(testContextInstance. DataRow["ExpectedTotalPrice"]);
actual = target.CalculateTotalPrice(Convert.ToDouble (testContextInstance.DataRow["UnitPrice"]),
Convert.ToInt32(testContextInstance. DataRow["Quantity"]));
Assert.AreEqual(expected, actual, "The expected value is {0} but the actual value is {1}", expected, actual);
Trace.WriteLine("Expected:" + expected + "; Actual:"+ actual);
}
Now open the Test View window and select the test method listed in the window.
On running the test, we can see
the test execution happening for each row in the data source. Once the
test has been completed for all of the rows in the data source, we can
see the test result based on the results of all individual tests. Even
if one test fails, the end result of the test run will be a failure. To
get the test run to pass, all of the individual tests within the
selected test run should pass.
The output for the above
test with the data source having five records in it, as shown in the
previous screenshot, the test result would be:
We can see the total time taken for each test and the row picked for
each test from the above result. All five tests fail and you can see the
custom error message displayed with the expected and actual values
applied to the formatters. All the tests fail because of the calculation
mistake in the actual method. The data source contains the expected
value based on the tax value as 0.12 but the actual method has the value
as 0.125. If you change the value to 0.12 in the method CalculateTotalPriceTest and rerun the test, the test would pass.
The Test Run details window shows the status of each test run for each row in the data source.